//Lindsay Ergenekan 
//ergenekl@onid.oregonstate.edu 
//CS311 - 400
//Homework 6 - Twin Primes

//ll /dev/shm to see the shared memory

//ps aux | grep $LOGNAME | grep -v root

#include "hw5.h"

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0)
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7));
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF;


int main(int argc, char *argv[])
{
    unsigned int maxNumber = UINT_MAX;

 //   unsigned int maxNumber = 500;
    unsigned char *bitmap;
    long object_size;
    long x, j, i, m, n, bitmap_size; //variable for the process counts
    int numProc = 2;
  //  int sq_rt; 
    struct shm_buf * s_info; //declare the sem_info struct
    void * addr; 
    int value; 
    unsigned int numCalc = maxNumber; 
    unsigned long int sq_rt = sqrt(maxNumber);
    int c, printPrime; 

//    void *addr = mount_shmem ("test1", object_size);


  //  fprintf(stdout, "addr = %x\n",  addr);
  while ((c = getopt(argc, argv, "n:m:p")) != -1)
    switch (c){ 
        case 'n':
            numCalc = atol(optarg); 
            break;
       case 'm':
            numProc= atoi(optarg);
            break;
        case 'p':
            printPrime = 1;
            break;
        }

        printf("numCalc (%lu) \n", numCalc);
        printf("numThread (%lu) \n", numProc);
        printf("printPrime (%lu) \n", printPrime);

    bitmap_size = (maxNumber/8)+1;
    object_size = bitmap_size + sizeof(struct shm_buf);

    shm_unlink ("test1");
    shmem_fd = shm_open("test1", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);

    if (shmem_fd == -1){
        fprintf(stdout, "failed to open shared memory object");
        exit(EXIT_FAILURE);
    }
    
    //resize the memory space
    if(ftruncate(shmem_fd, object_size) ==-1){
        fprintf(stdout,  "failed to resize shared memory object");
        exit(EXIT_FAILURE);
    }
    
    //get the path.. leave address to NULL for portability. this allows kernel to choose
    s_info = mmap(NULL, object_size, PROT_READ  | PROT_WRITE, MAP_SHARED, shmem_fd, 0); //0 is offset(how far into it is 0 address)
 //   bitmap = (unsigned char *) s_info + sizeof(struct shm_buf);
    
    sem_init(&s_info->sem, 1, 1);        
    sem_getvalue(&s_info->sem, &value); 
    printf("The value of the semaphors is %d\n", value);

  //  bitmap = (unsigned char*) addr + sizeof(struct shm_buf); 
   // prime_numbers = (int*) (bitmap + bitmap_size); 
    bitmap = (unsigned char *) s_info + sizeof(struct shm_buf);
  //  printf("the address of bitmap is: (%p) \n", &bitmap);
   // printf("the size of bitmap is: (%d) \n", sizeof(bitmap));
    

   SETBIT(bitmap, 1); //set bit 1
 //SETBIT(bitmap, 2); //set bit 2

for (x = 1; x<(numProc); ++x){
        switch(j = fork()){
            case 0: 
               
                printf("in the child (%d) \n", x);
                sem_getvalue(&s_info->sem, &value); 
  //              printf("The value of the semaphors is %d\n", value);

                sem_wait(&s_info->sem);

//                sem_getvalue(&s_info->sem, &value); 
//                printf("The value of the semaphors AFTER WAIT is %d\n", value);
             




 //               printf("in the middle");
             for(i = 2; i <= sq_rt; i++)
            {
                 if(!ISBITSET(bitmap,i))
                {
                    for (j = i*i; j <= maxNumber; j += i)
                    {
                        if(!ISBITSET(bitmap, j)){
//                    pthread_mutex_lock();
                        SETBIT(bitmap,j); 
//                    pthread_mutex_unlock();
                        } 
 //                       else
 //                       printf("not set (%d) \n", j);   
                    }
                }
            }





  //              sem_getvalue(&s_info->sem, &value); 
 //               printf("The value of the semaphors is %d\n", value);

                sem_post(&s_info->sem);
 //                               sem_getvalue(&s_info->sem, &value); 
 //               printf("The value of the semaphors AFTER POST is %d\n", value);
                

                _exit(EXIT_SUCCESS);//finished now. time to go back to parent
                break;
            case -1:
                //error case
                printf("Error creating child (%d) \n", x);
                exit(-1);
                break;
            default:
                break;
                //parent case
        }
    }


//wait on all of the children
for(x = 0; x <numProc; x++){
        printf("Waiting for child (%d) \n", x);    
        wait(NULL); //parents just wait on children
}

    sem_destroy(&s_info->sem);


    printf("about to read out the bit array");




  for ( i = 2; i < maxNumber-1; ++i ){
        if (!ISBITSET(bitmap, i) && !ISBITSET(bitmap,(i+2))){
                printf("PRIME %lu !\n", i);
            }
        }
         



/*
  for ( i = 3; i < (max_size-1); ++i ){
        if (!ISBITSET(bitmap, i)){
                printf("PRIME %d !\n", i);
            }
        }
*/

    return 0;
}



void * sieve(void *arg)
{

    int i, j, sq_rt;
    int up_to_num; //varialbe to record where to end
    struct thread_info * bitMAP;
    unsigned char * map;
    bitMAP = (thread_info *) arg;
    map = bitMAP->bitMAP;
    up_to_num = bitMAP->up_to_num;
    sq_rt = sqrt(5000);

    printf("sq_rt %d \n", sq_rt);


    for(i = 2; i <= sq_rt; i++)
    {
        if(!ISBITSET(map,i))
        {
            for (j = i*i; j <= 5000; j += i)
            {
                if(!ISBITSET(map, i)){
//                    pthread_mutex_lock();
                        SETBIT(map,j); 
//                    pthread_mutex_unlock();
                }    
            }
        }
    }
        pthread_exit((void*)0);//exit the thread
}

/*
//code from lecture to make shared memory
void *mount_shmem(char *path, int object_size){

    void * addr;

    //open and check a shared memory file descriptor
    shmem_fd = shm_open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (shmem_fd == -1){
        fprintf(stdout, "failed to open shared memory object");
        exit(EXIT_FAILURE);
    }
    
    //resize the memory space
    if(ftruncate(shmem_fd, object_size) ==-1){
        fprintf(stdout,  "failed to resize shared memory object");
        exit(EXIT_FAILURE);
    }
    
    //get the path.. leave address to NULL for portability. this allows kernel to choose
    addr = mmap(NULL, object_size, PROT_READ  | PROT_WRITE, MAP_SHARED, shmem_fd, 0); //0 is offset(how far into it is 0 address)
    if(addr == MAP_FAILED){
        fprintf(stdout, "failed to map shared memory object");
        exit(EXIT_FAILURE);
    }
    
    return addr;
}
*/